home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gekikoh Dennoh Club 2
/
Gekikoh Dennoh Club Vol. 2 (Japan).7z
/
Gekikoh Dennoh Club Vol. 2 (Japan) (Track 01).bin
/
tools
/
psmed
/
psmed01.lzh
/
source
/
psmed.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-09-04
|
18KB
|
949 lines
/*######################################
* X68 Human68k
* psmed:汎用PSMデータエディタ
*
* psmed.c メインモジュール
*
* by BLACK.
*######################################
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#include <io.h>
#include <errno.h>
#include <process.h>
#include <doslib.h>
#define GLOBAL_MEM
#include "psmed.h"
#define VER 0.1
#define PAGETITLE_X 0 /* ページタイトル表示位置 */
#define PAGETITLE_Y 2
#define EDIT_X 0 /* 編集リスト表示位置 */
#define EDIT_Y 4
#define ITEMEDIT_X 0 /* アイテム編集表示位置 */
#define ITEMEDIT_Y 30
#define PAGE_X 80 /* ページ表示位置 */
#define PAGE_Y 0
#define PROTECT_X 60 /* 書き込み禁止表示位置 */
#define PROTECT_Y 0
/*━━━━━━━━━━━━━━━━━━━━━━*/
static int block_num; /* 編集PSMファイルのブロック長 */
static unsigned char headerbuf[BLOCK_MAX][HEADER_LEN]; /* PSMブロックヘッダ保存 */
static unsigned char psmbuf[BLOCK_LEN*BLOCK_MAX]; /* ブロックデータ内容 */
static char fnk[6] = ""; /* CLRキー定義内容退避 */
/*━━━━━━━━━━━━━━━━━━━━━━*/
void help(void);
void init(void);
void tini(void);
edit_t *pagetolist(int page);
void screen_init(void);
static void pagedisp(int page);
static void page_item_disp(int no);
void edit(void);
void edit_item(int no);
void edit_item_n(int no);
static void item_mark(int no);
static void make_ped_filename(char *out,const char *flnm);
static void search_ped(char *out,const char *flnm);
/*━━━━━━━━━━━━━━━━━━━━━━*/
/**********************
* main
*
*
**********************
*/
int main(int argc,char *argv[])
{
int f_count; /* コマンドオプション パス名取得用 */
FILE *fp;
int i;
char drv[4];
char path[FILENAME_MAX];
char ext[4];
char bak_filename[FILENAME_MAX];
size_t len;
int opt_b = FALSE;
int msg_f = FALSE;
enum e_no_tag{
e_nomsg,
e_noexec,
e_execfailure,
e_execnomem,
}msg_no = e_nomsg;
char flnm1[FILENAME_MAX];
char flnm2[FILENAME_MAX];
init();
atexit(tini);
/*=== コマンドオプション処理 ===*/
if (argc <= 1){
help();
return EXIT_FAILURE;
}
strsfn(argv[0],drv,path,NULL,NULL);
strcpy(base_path,drv);
strcat(base_path,path);
f_count = 0;
for (i = 1;i < argc;i++){
if (argv[i][0] == '-' || argv[i][0] == '/'){
/* オプションスイッチ処理 */
switch (argv[i][1]){
case '?':
/* Help */
help();
return EXIT_FAILURE;
case 'b':
case 'B':
opt_b = TRUE;
break;
case 'v':
case 'V':
write_protect = TRUE;
break;
default:
/* それ以外は無視 */
break;
}
}else{
/* パス名処理 */
switch (f_count){
case 0:
strcpy(flnm1,argv[i]);
break;
case 1:
strcpy(flnm2,argv[i]);
break;
default:
/* 受け取り数以降は無視 */
break;
}
f_count++;
}
}
switch (f_count){
case 1:
search_ped(flnm2,flnm1);
if (strlen(flnm2) == 0){
puts("編集情報検索に失敗しました。");
return EXIT_FAILURE;
}
make_ped_filename(cnf_filename,flnm2);
if (!cnf_read(cnf_filename)){
puts("編集情報取り込みに失敗しました。");
return EXIT_FAILURE;
}
strcpy(filename,flnm1);
case 2:
make_ped_filename(cnf_filename,flnm1);
if (!cnf_read(cnf_filename)){
puts("編集情報取り込みに失敗しました。");
return EXIT_FAILURE;
}
strcpy(filename,flnm2);
break;
default:
help();
return EXIT_FAILURE;
}
if (opt_b){
cnfoption_b = TRUE; /* バックアップ無し */
/* コマンドオプションが優先する */
}
/*=== PSMデータ読み込み ===*/
stcgfe(ext,filename);
if (strcmpi(ext,"psm")){
puts("このファイルはPSMファイルではありません。");
return EXIT_FAILURE;
}
/* バッファへファイル取り込み */
fp = fopen(filename,"r+b");
if (!fp){
puts("ファイルのオープンに失敗しました。");
return EXIT_FAILURE;
}
block_num = filelength(fileno(fp)) / (HEADER_LEN+BLOCK_LEN);
for (i=0;i<block_num;i++){
fread(headerbuf[i],sizeof(char),HEADER_LEN,fp);
fread(psmbuf+i*BLOCK_LEN,sizeof(char),BLOCK_LEN,fp);
}
fclose(fp);
if (strncmp(headerbuf[0]+12,psm_id,strlen(psm_id))){
puts("編集情報とPSMファイルで対象が違っています。");
return EXIT_FAILURE;
}
/*=== 編集 ===*/
screen_init();
edit();
/*=== PSMデータ保存 ===*/
if (psm_edited && !write_protect){
if (!cnfoption_b){
strmfe(bak_filename,filename,"bak");
if (rename(filename,bak_filename) < 0){
remove(bak_filename);
rename(filename,bak_filename);
}
}
fp = fopen(filename,"wb");
for (i=0;i<block_num;i++){
len = fwrite(headerbuf[i],sizeof(char),HEADER_LEN,fp);
if (len != HEADER_LEN){
puts("書き込み容量エラー");
break;
}
len = fwrite(psmbuf+i*BLOCK_LEN,sizeof(char),BLOCK_LEN,fp);
if (len != BLOCK_LEN){
puts("書き込み容量エラー");
break;
}
}
fclose(fp);
if (c_prog_argv[0]){
if (execvp(c_prog_argv[0],c_prog_argv) == -1){
switch (errno){
case ENOMEM: msg_no = e_execnomem; break;
default: msg_no = e_execfailure; break;
}
msg_f = TRUE;
}else{
msg_f = FALSE;
}
}else{
msg_f = TRUE;
msg_no = e_noexec;
}
}
C_FNKMOD(0);
C_CLS_AL();
if (msg_f){
switch (msg_no){
case e_noexec:
puts("警告:チェックサム補正プログラムが定義されていません。");
break;
case e_execnomem:
puts("メモリーエラーでチェックサム補正プログラム実行が出来ませんでした。");
break;
case e_execfailure:
puts("チェックサム補正プログラム実行が出来ませんでした。");
break;
default:
break;
}
}
return EXIT_SUCCESS;
}
/********************
* init
* 初期化処理
*
********************
*/
void init(void)
{
int i;
editlist = NULL;
editlistlast = NULL;
listnum = 0;
cnfoption_a = FALSE;
cnfoption_b = FALSE;
psm_edited = FALSE;
write_protect = FALSE;
for (i=0;i<MENU_MAX;i++){
menu[i] = NULL;
menu_item_num[i] = 0;
menu_items[i] = NULL;
menu_items_num[i] = 0;
}
}
/********************
* tini
* 終了処理
*
********************
* atexit()によって登録されるから終了時は必ず実行される
*/
void tini(void)
{
edit_t *item;
edit_t *next;
int i;
/* 編集リストの解放 */
if (editlist){
item = editlist;
do{
next = item->next;
free(item);
item = next;
}while (next != NULL);
}
/* メニューの解放 */
for (i=0;i<MENU_MAX;i++){
free(menu[i]);
}
/* ファンクションキーを戻す */
if (fnk[0]){
FNCKEYST(f_clr,fnk);
}
C_CURON();
}
/***********************
* help
*
*
***********************
* ヘルプ処理はちゃんとしないとな。うむ。
*/
void help(void)
{
printf("psmed v%.1f by BLACK.\n",VER);
puts("編集情報(*.ped)でPSMファイルを編集出来ます。");
puts("Ex.>psmed [option] <*.ped> <*.psm>");
puts("option");
puts(" -b バックアップファイルを作成しない");
puts(" -v 書き込み禁止");
}
/***************************
* screen_init
* 画面初期化
*
***************************
* SXのコンソールウィンドウでも実行可能な様に
* コンソールだけで画面を構成する方針である。
* エスケープシーケンスの強調が使えなかったような気もするが・・・
*/
void screen_init(void)
{
int i;
C_FNKMOD(3);
C_CLS_AL();
C_CUROFF();
FNCKEYGT(f_clr,fnk);
FNCKEYST(f_clr,"\033E"); /* CLRをVOIDに割り当てる */
C_LOCATE(0,0);
printf("PSMED Ver%.1f Edit:%s",VER,headerbuf[0]+12);
C_LOCATE(0,1);
printf("%s",psmbuf+4);
if (write_protect){
C_LOCATE(PROTECT_X,PROTECT_Y);
fputs("\x1b[36m書込禁止\x1b[m",stdout);
}
C_LOCATE(0,EDIT_Y-1);
fputs("\x1b[37m",stdout);
for (i=0;i<48;i++){
fputs(" ̄",stdout);
}
fputs("\x1b[m",stdout);
C_LOCATE(0,EDIT_Y+PAGE_ITEM_MAX);
for (i=0;i<48;i++){
fputs("─",stdout);
}
pagedisp(0);
}
/***************************
* pagedisp
* ページ番号からページ表示
*
***************************
* 内部でpageedit[]を作っているのは一見無駄に見えるかも知らんが
* 編集コマンドの分だけを集めたリストを別に作った方が便利なんだね。
* ページとアイテム番号からリスト内をその都度検索するより。
*/
static void pagedisp(int page)
{
edit_t *rec;
int i,j;
int pagetitle = FALSE;
/* ページリストと画面のページ内容初期化 */
for (i=0;i<PAGE_ITEM_MAX;i++){
pageedit[i] = NULL;
C_LOCATE(EDIT_X,EDIT_Y+i);
C_ERA_AL();
}
C_LOCATE(PAGE_X,PAGE_Y);
printf("Page:%3d/%3d",page + 1,editlistlast->page + 1);
/* 項目名 */
rec = pagetolist(page);
for (i=0,j=0;i<PAGE_ITEM_MAX;i++){
if (rec->page != page){
break;
}
switch (rec->cmd){
case c_pagetitle:
C_LOCATE(PAGETITLE_X,PAGETITLE_Y);
printf("\x1b[37m/\x1b[35m%s\x1b[37m\\x1b[m",rec->name);
C_ERA_ED();
pagetitle = TRUE;
break;
case c_edit_b:
case c_edit_w:
case c_edit_l:
case c_edit_s:
case c_menu_b:
case c_menu_w:
case c_menu_l:
pageedit[j] = rec; /* 登録するのは編集コマンドのみ */
j++;
C_LOCATE(EDIT_X,EDIT_Y+rec->item);
fputs(rec->name,stdout);
break;
case c_title:
C_LOCATE(EDIT_X,EDIT_Y+rec->item);
printf("\x1b[31m%s\x1b[m",rec->name);
break;
}
rec = rec->next;
if (!rec){
break;
}
}
if (!pagetitle){
C_LOCATE(PAGETITLE_X,PAGETITLE_Y);
fputs("\x1b[37m/ ̄ ̄ ̄ ̄\\x1b[m",stdout);
C_ERA_ED();
}
/* 項目内容 */
for (i=0;i<PAGE_ITEM_MAX;i++){
page_item_disp(i);
}
item_mark(-1);
}
/***************************
* page_item_disp
* ページ内アイテム番号から内容表示
*
***************************
*/
static void page_item_disp(int no)
{
edit_t *rec;
if (!pageedit[no]){
return;
}
rec = pageedit[no];
C_LOCATE(EDIT_X+ITEM_NAME_LEN,EDIT_Y+rec->item);
switch (rec->cmd){
case c_edit_b:
printf("%12u",bufget(rec->adr,1));
break;
case c_edit_w:
printf("%12u",bufget(rec->adr,2));
break;
case c_edit_l:
printf("%12u",bufget(rec->adr,4));
break;
case c_edit_s:
printf("%-*s",rec->size,psmbuf + rec->adr);
break;
case c_menu_b:
if (menu[rec->size]){
printf("%-*s",MENU_ITEM_NAME_LEN,menu[rec->size]+MENU_ITEM_NAME_LEN*bufget(rec->adr,1));
}
break;
case c_menu_w:
if (menu[rec->size]){
printf("%-*s",MENU_ITEM_NAME_LEN,menu[rec->size]+MENU_ITEM_NAME_LEN*bufget(rec->adr,2));
}
break;
case c_menu_l:
if (menu[rec->size]){
printf("%-*s",MENU_ITEM_NAME_LEN,menu[rec->size]+MENU_ITEM_NAME_LEN*bufget(rec->adr,4));
}
break;
default:
break;
}
}
/***************************
* edit
* 編集処理
*
***************************
*/
void edit(void)
{
int loop_f = TRUE;
int key;
int page = 0;
int item = 0;
while (loop_f){
key = inkey();
switch (key){
case ESC:
loop_f = FALSE;
break;
case ROLL_UP:
page++;
if (page > editlistlast->page){
page = editlistlast->page;
break;
}
item = 0;
pagedisp(page);
break;
case ROLL_DOWN:
page--;
if (page < 0){
page = 0;
break;
}
item = 0;
pagedisp(page);
break;
case UP:
item--;
if (item < 0){
item = 0;
break;
}
item_mark(item);
break;
case DOWN:
item++;
if (item >= PAGE_ITEM_MAX || pageedit[item] == NULL){
item--;
break;
}
item_mark(item);
break;
case CR:
if (!write_protect){
edit_item(item);
switch (pageedit[item]->cmd){
case c_menu_b:
case c_menu_w:
case c_menu_l:
pagedisp(page); /* メニューの時は画面描き直し */
break;
default:
break;
}
}
break;
case 'v':
case 'V':
write_protect = TRUE;
C_LOCATE(PROTECT_X,PROTECT_Y);
fputs("\x1b[36m書込禁止\x1b[m",stdout);
break;
default:
break;
}
}
}
/**********************
* item_edit
* 項目編集
*
**********************
*/
void edit_item(int no)
{
switch (pageedit[no]->cmd){
case c_edit_b:
case c_edit_w:
case c_edit_l:
case c_edit_s:
edit_item_n(no);
break;
case c_menu_b:
case c_menu_w:
case c_menu_l:
edit_item_m(no);
break;
default:
break;
}
}
/**********************
* item_edit
* 数値項目編集
*
**********************
*/
void edit_item_n(int no)
{
struct INPPTR instr;
instr.max = STR_BUFFER_LEN;
C_CURON();
C_LOCATE(ITEMEDIT_X,ITEMEDIT_Y);
fputs("Input:",stdout);
GETSS(&instr); /* History.x 機能が使えるから文字列入力はDOSコールを使おうぜぇ */
/* 同じ手抜きでもfgets()とかを使う位ならね。ファイル名補完機能も有るんじゃけん */
C_LOCATE(ITEMEDIT_X,ITEMEDIT_Y);
C_ERA_ED();
C_CUROFF();
if (instr.length == 0){
return;
}
switch (pageedit[no]->cmd){
case c_edit_b:
bufset(pageedit[no]->adr,1,strtol2(instr.buffer));
psm_edited = TRUE;
break;
case c_edit_w:
bufset(pageedit[no]->adr,2,strtol2(instr.buffer));
psm_edited = TRUE;
break;
case c_edit_l:
bufset(pageedit[no]->adr,4,strtol2(instr.buffer));
psm_edited = TRUE;
break;
case c_edit_s:
strncpy(psmbuf+pageedit[no]->adr,instr.buffer,pageedit[no]->size);
psmbuf[pageedit[no]->adr + pageedit[no]->size - 1] = '\0';
psm_edited = TRUE;
break;
default:
break;
}
page_item_disp(no);
}
/**********************
* item_mark
* 項目に選択用カラーを付ける。
*
**********************
*/
static void item_mark(int no)
{
static int old;
edit_t *rec;
if (no < 0){
/* 初期化用 */
old = 0;
rec = pageedit[0];
C_LOCATE(EDIT_X,EDIT_Y+rec->item);
printf("\x1b[41m%-*s\x1b[m",ITEM_NAME_LEN-1,rec->name);
return;
}
if (old == no){
return; /* マークは移動していない */
}
rec = pageedit[no];
C_LOCATE(EDIT_X,EDIT_Y+rec->item);
printf("\x1b[41m%-*s\x1b[m",ITEM_NAME_LEN-1,rec->name);
rec = pageedit[old];
C_LOCATE(EDIT_X,EDIT_Y+rec->item);
printf("\x1b[m%-*s",ITEM_NAME_LEN-1,rec->name);
old = no;
}
/***************************
* pagetolist
* ページ番号から編集リストの先頭を得る
*
* out:リストのポインタ
***************************
*/
edit_t *pagetolist(int page)
{
edit_t *rec;
if (page == 0){
return editlist;
}
rec = editlist;
while (rec->page != page){
rec = rec->next;
if (rec == NULL){
rec = editlist;
break;
}
}
return rec;
}
/***************************
* bufget
* PSMデータバッファからデータを得る
*
* in adr=アドレス size=データサイズ
***************************
* PSはスモールエンディアン
*/
int bufget(int adr,int size)
{
int d = 0;
switch (size){
case 1:
d = psmbuf[adr];
break;
case 2:
d = psmbuf[adr];
d += psmbuf[adr+1]*0x100;
break;
case 4:
d = psmbuf[adr];
d += psmbuf[adr+1]*0x100;
d += psmbuf[adr+2]*0x10000;
d += psmbuf[adr+3]*0x1000000;
break;
}
return d;
}
/***************************
* bufset
* PSMデータバッファにデータを設定
*
* in adr=アドレス size=データサイズ data=設定値
***************************
* PSはスモールエンディアン
*/
void bufset(int adr,int size,int data)
{
switch (size){
case 1:
psmbuf[adr] = data;
break;
case 2:
psmbuf[adr] = data % 0x100;
psmbuf[adr+1] = data / 0x100;
break;
case 4:
psmbuf[adr] = data & 0xff;
psmbuf[adr+1] = data >> 8 & 0xff;
psmbuf[adr+2] = data >> 16 & 0xff;
psmbuf[adr+3] = data >> 24 & 0xff;
break;
}
}
/**********************
* inkey
* キー入力
*
**********************
*/
int inkey(void)
{
int key;
key = K_KEYBIT(7); /* DOSコールの方を使おうぜぇ */
if (key & 0x01){
key = ROLL_UP;
}else if (key & 0x02){
key = ROLL_DOWN;
}else if (key & 0x08){
key = LEFT;
}else if (key & 0x10){
key = UP;
}else if (key & 0x20){
key = RIGHT;
}else if (key & 0x40){
key = DOWN;
}else{
return getch();
}
while (K_KEYBIT(7));
return key;
}
/***************************
* strtol2
* 文字列を数値変換(16進数$表記対応)
*
* out:値
***************************
*/
int strtol2(const char *str)
{
char str2[32];
int d;
if (str[0] == '$'){ /* 16進接頭文字 */
if (strlen(str)+3 > sizeof(str2)){
return 0; /* 変換失敗 */
}
strcpy(str2,"0x");
strcat(str2,str+1);
d = strtol(str2,NULL,0);
}else{
d = strtol(str,NULL,0);
}
return d;
}
/**************************
* xmalloc
* 自動ヒープ拡張付きmalloc
*
*
**************************
* XCライブラリのmalloc()はヒープを拡張しないので
*/
void *xmalloc(size_t size)
{
void *buf;
if (size <= 0) return NULL;
buf = malloc(size);
if (buf == NULL){
if (sbrk(size) == (void*)-1){
errno = ENOMEM;
return NULL;
}
buf = malloc(size);
if (buf == NULL){
errno = ENOMEM;
return NULL;
}
}
return buf;
}
/***************************
* make_ped_filename
* 編集情報ファイル名作成
*
***************************
*/
static void make_ped_filename(char *out,const char *flnm)
{
FILE *fp;
char drv[4];
char path[FILENAME_MAX];
char node[20];
char ext[4];
strsfn(flnm,drv,path,node,ext);
fp = fopen(flnm,"r");
if (!fp){
/* 見つからなかったら実行ファイルのパスを格納 */
strcpy(out,base_path);
strcat(out,"\\");
strcat(out,node);
strcat(out,".");
if (strlen(ext) == 0){
strcat(out,"ped"); /* 拡張子補完 */
}else{
strcat(out,ext);
}
}else{
fclose(fp);
strcpy(out,flnm);
if (strlen(ext) == 0){
strcat(out,".ped"); /* 拡張子補完 */
}
}
}
/***************************
* search_ped
* 編集情報ファイル名検索
*
***************************
* 工事中
*/
static void search_ped(char *out,const char *flnm)
{
char id[32];
FILE *fp;
fp = fopen(flnm,"rb");
if (!fp){
out[0] = '\0';
return;
}
fseek(fp,12,SEEK_SET);
fgets(id,sizeof id,fp);
fclose(fp);
out[0] = '\0';
}